/*
 * MyThread.java
 *
 * Created on November 16, 2004, 2:32 PM
 */

package edu.umd.essic.maskbuilder;


import java.io.*;
import java.awt.geom.Point2D;
import java.awt.Point;
import java.lang.Math;
import java.nio.*;
import java.nio.channels.*;
import javax.swing.JOptionPane; 

public class FThread extends Thread{
    Int_Dialog IDialog;
    Grid gg;
    private boolean NeedToSplit = false;
    private boolean NoData = false;
    private int nb_species, nb_species_file, nb_series, nb_fishery;
    private static int FUNC;
    private static boolean BinaryFormat;
    private static int Criterion;
    private Point2D.Double[][] coord, metric;
    private int size_x, size_y, nlon, nlat, nlon_mr, nlat_mr, filereso, inputformat, nrecords;
    private float startdate_all, enddate_all;
    private float lon_min, lat_min, lon_max, lat_max; //data domain corners
    private float lonmin, lonmax, latmin, latmax; //current domain corners
    private File[] inputbin, outputbin;
    private float[][] xcrd, ycrd, var, region;
    private float[][][][] catch_obs;
    private float[][][] effort_obs;
    private int[] mr_species, nb_data;
    private boolean cell_centered = false;
    private float firstrec = 2010;
    
    /** Creates a new instance of MyThread */
    public FThread(File input_par, Grid grid, boolean mask_type) {
       FUNC = grid.Get_StrType();
       gg = grid;
       coord = grid.Get_Re_Coords();
       if (mask_type){
           gg.SetCenteredGrid();
           cell_centered = true;
       }
       size_x = gg.Get_NX();
       size_y = gg.Get_NY();
       lonmin = gg.getLonMin(); lonmax = gg.getLonMax();   
       latmin = gg.getLatMin(); latmax = gg.getLatMax(); 
       double[][] mx = new double[size_x][size_y];
       double[][] my = new double[size_x][size_y];
       metric = new Point2D.Double[size_x][size_y];
       gg.GetMetrics(mx,my);
       for(int i=0;i<size_x;i++){
            for(int j=0;j<size_y;j++){
                metric[i][j] = new Point2D.Double(mx[i][j],my[i][j]);
           }
       }
       mx = null; my = null;
       ReadParFile(input_par);
       IDialog = new Int_Dialog(null);
       IDialog.setLocation(20,20);
       IDialog.jProgressBar1.setStringPainted(true);
       IDialog.setTitle("Catch data processing");
       IDialog.show();
    }
    
    public void run() {      
        float[][][] effort_mr;
        float[][][][] catch_mr;
        int k = 0;
        String LogMsg = "The following files were successfully written: ";
        while((k<nb_fishery) && (IDialog.getReturnStatus())){ 
            boolean AppendMode = false;
            String title = "Catch data processing: " + inputbin[k].getName();
            IDialog.jProgressBar1.setValue(0);
            IDialog.setTitle(title);
            ReadFileHeader(inputbin[k]);
            ReadDataParamForFleet(inputbin[k]);
            if (NoData) continue;
            effort_obs = new float[nb_series][nlon][nlat];
            catch_obs  = new float[nb_series][nb_species][nlon][nlat];
            nb_data    = new int[nb_series];
            ReadFile(inputbin[k]);
            if (Criterion == 0)
                GetDataLengthForDate(catch_obs);
            else if (Criterion == 1)
                GetDataLengthForDate(effort_obs);
            else if (Criterion == 2)
                GetDataLengthForDate(effort_obs,catch_obs);
            if ((FUNC > 0)||(NeedToSplit)){
                title = "Catch data processing: redistributing " + inputbin[k].getName();
                IDialog.setTitle(title);
                effort_mr  = new float[nb_series][nlon_mr][nlat_mr];
                catch_mr   = new float[nb_series][nb_species][nlon_mr][nlat_mr]; 
                for (int t=0; t<nb_series; t++){
                    Redistribute(effort_obs[t], effort_mr[t], t);
                    for(int sp=0; sp<nb_species; sp++)
                        Redistribute(catch_obs[t][sp], catch_mr[t][sp], t);
                    GetRDataLengthForDate(effort_mr[t],catch_mr[t],t);
                    int prDone = (int) ((t+1)*100.0/nb_series);
                    IDialog.jProgressBar1.setValue(prDone); 
                }
                title = "Catch data processing: write to file " + outputbin[k].getName();
                IDialog.jProgressBar1.setValue(0);
                IDialog.setTitle(title);
                WriteFile(outputbin[k], effort_mr, catch_mr, nlon_mr, nlat_mr, BinaryFormat);
                effort_mr  = null;
                catch_mr   = null;
            } else {
                for (int t=0; t<nb_series; t++){
                    WriteFile(outputbin[k], effort_obs[t], catch_obs[t], t, nlon, nlat, AppendMode, BinaryFormat);
                    AppendMode = true;
                    int prDone = (int) ((t+1)*100.0/nb_series);
                    IDialog.jProgressBar1.setValue(prDone);
                }
            }
            LogMsg += "\n" + outputbin[k].getAbsolutePath(); 
            effort_obs = null; 
            catch_obs  = null;
            k++;
        }
        LogMsg += "\n" + "First record is in " + String.valueOf(getMonth(firstrec))+"/"+String.valueOf((int)firstrec);
        IDialog.doClose();
        IDialog = null;
        if (cell_centered)
            gg.SetNodeGrid(coord);
        JOptionPane.showMessageDialog(null,LogMsg,"Summary",JOptionPane.INFORMATION_MESSAGE);
    }
   
    private void ReadParFile(File file_par){
        String line = "";
        String[] species_name;
        try{
            BufferedReader r = new BufferedReader(new FileReader(file_par));
            Pos p = new Pos();
            line = r.readLine();
            nb_fishery = p.ReadInt(line); 
            p.SetZero();
            line = r.readLine();
            nb_species_file= p.ReadInt(line);
            p.SetZero();
            mr_species = new int[nb_species_file];
            species_name = new String[nb_species_file];
            int count = 0;
            for (int i=0; i<nb_species_file; i++){
                line = r.readLine();
                species_name[i] = p.ReadString(line);
                mr_species[i] = p.ReadInt(line);
                p.SetZero();
                count += mr_species[i];
            }
            nb_species = count;
            inputbin = new File[nb_fishery];
            outputbin = new File[nb_fishery];
            line = r.readLine();
            inputformat = p.ReadInt(line);
            p.SetZero();
            line = r.readLine();
            Criterion = p.ReadInt(line);
            p.SetZero();
            line = r.readLine();
            int format = p.ReadInt(line);
            if (format == 1)
                BinaryFormat = true;
            else if (format == 0)
                BinaryFormat = false;
            r.readLine();
            String species = "";
            for (int i=0; i<nb_species_file; i++){
                if (mr_species[i] !=0)
                    species += "_"+species_name[i];
            }
            if (FUNC > 0)
                species += "_mr";
            if (BinaryFormat)
                species += ".bin"; 
            else 
                species += ".txt";
            p.SetZero();
            for (int num=0; num<nb_fishery; num++){
                line = r.readLine();
                if (line == null){
                    nb_fishery = num;
                    break;
                }
                String name = p.ReadString(line);
                inputbin[num] = new File(name);
                String pathname = inputbin[num].getAbsolutePath();
                int ss = pathname.indexOf(".");
                String pathname_outp = pathname.substring(0,ss)+species;
                outputbin[num]= new File(pathname_outp);
                p.SetZero();
            } 
            p = null;
        }catch (IOException e) {
            Utils.FileReadError(file_par.getName());
        }
    }
    
    private void ReadFileHeader(File fi){
        if (inputformat==1)
            ReadBinFileHeader(fi);
        else
            ReadTextFileHeader(fi);
    }
    
    private void ReadFile(File fi){
        if (inputformat==1)
            ReadBinFile(fi);
        else
            ReadTextFile(fi);
    }
    
    private void ReadBinFileHeader(File inputbin){
        ByteBuffer dim_buffer = null;
        int buflen = (6+nb_species_file*2)*4; 
        dim_buffer = ByteBuffer.allocate(buflen);
        try {
            FileInputStream fileInput = new FileInputStream(inputbin);
            FileChannel fc = fileInput.getChannel();
            fc.read(dim_buffer); 
            dim_buffer.order(ByteOrder.LITTLE_ENDIAN);
            dim_buffer.rewind();
            //=== First Year ===================
            float fyear = dim_buffer.getFloat();
            //=== First Month ==================
            float fmonth = dim_buffer.getFloat();
            //=== Last Year ====================
            float lyear = dim_buffer.getFloat();
            //=== Last Month ===================
            float lmonth = dim_buffer.getFloat();
            int nbs   = (int)dim_buffer.getFloat();
            filereso  = (int) dim_buffer.getFloat();
        } catch (IOException e) {
            Utils.FileReadError(inputbin.getName());
        }
    }
    
    private void ReadTextFileHeader(File inputtxt){
        try {
            BufferedReader r = new BufferedReader(new FileReader(inputtxt));
            r.readLine();
            Pos p = new Pos();
            String line = r.readLine();
            //=== First Year ===================
            float fyear = p.ReadFloat(line);
            //=== First Month ==================
            float fmonth = p.ReadFloat(line);
            //=== Last Year ====================
            line = r.readLine();
            float lyear = p.ReadFloat(line);
            //=== Last Month ===================
            float lmonth = p.ReadFloat(line);
            int nbs   = (int)Float.parseFloat(r.readLine());
            filereso   = (int)Float.parseFloat(r.readLine());
        } catch (IOException e) {
            Utils.FileReadError(inputtxt.getName());
        }
       enddate_all = 0;
       startdate_all = 10000;        
    }
        
    //===================================================
    // Routine finds the regions where data is available,
    // calculates the enddate of data available, nb_series 
    // and dimension of submatrices for each fleet
    //===================================================    
    private void ReadDataParamForFleet(File inputbin){
       float[][] rec_date;
       lon_min = 360; lon_max = 0;   
       lat_min = -90; lat_max = 90;  
       nrecords = 0;
       if (inputformat==0) ReadParamsTextFile(inputbin);
       else {
           NoData = false;
           ByteBuffer dim_buffer = null;
           int header_size = (6+nb_species_file*2)*4;
           int buffer_size = (4+1+nb_species_file)*4;
           int nbytetoread = (int)inputbin.length()-header_size;
           nrecords = nbytetoread/buffer_size;
           rec_date = new float[nrecords][nb_species];
           try{
               FileInputStream fileInput = new FileInputStream(inputbin);
               FileChannel fc = fileInput.getChannel();
               int fcpos = 0;
               while (fcpos < nrecords){
                   dim_buffer = ByteBuffer.allocate(buffer_size);
                   int nbytetoskip = header_size+fcpos*buffer_size;
                   fc.read(dim_buffer,nbytetoskip);
                   dim_buffer.order(ByteOrder.LITTLE_ENDIAN);
                   dim_buffer.rewind();        
                   //=== Find corners of region ============
                   float year  = dim_buffer.getFloat();
                   float month = dim_buffer.getFloat();
                   float lat = dim_buffer.getFloat();
                   float lon = dim_buffer.getFloat();
                   float effort = dim_buffer.getFloat();
                   int k=0;
                   if (Criterion == 1){
                       if (effort!=0){
                           if (lat_min < lat) lat_min = lat;
                           if (lat_max > lat) lat_max = lat;
                           if (lon < 0) lon += 360; 
                           if (lon_min > lon) lon_min = lon;
                           if (lon_max < lon) lon_max = lon;
                           for (int sp=0; sp<nb_species; sp++){
                            rec_date[fcpos][sp] = getDecimal(year,month);
                            if (rec_date[fcpos][k] == 0) continue;
                           }
                       }
                   } else if (Criterion == 0){
                       for (int sp=0; sp<nb_species_file; sp++){
                           float value =  dim_buffer.getFloat();                       
                           if ((value !=0) && (mr_species[sp]!=0)){
                               if (lat_min < lat) lat_min = lat;
                               if (lat_max > lat) lat_max = lat;
                               if (lon < 0) lon += 360; 
                               if (lon_min > lon) lon_min = lon;
                               if (lon_max < lon) lon_max = lon;
                               rec_date[fcpos][k] = getDecimal(year,month);
                               if (rec_date[fcpos][k] == 0) continue;
                               k++;
                           }
                       }
                   } else if (Criterion == 2){
                       for (int sp=0; sp<nb_species_file; sp++){
                           float value =  dim_buffer.getFloat();                       
                           if ((effort!=0) || (value !=0)){
                               if (mr_species[sp]!=0){
                                   if (lat_min < lat) lat_min = lat;
                                   if (lat_max > lat) lat_max = lat;
                                   if (lon < 0) lon += 360; 
                                   if (lon_min > lon) lon_min = lon;
                                   if (lon_max < lon) lon_max = lon;
                                   rec_date[fcpos][k] = getDecimal(year,month);
                                   if (rec_date[fcpos][k] == 0) continue;
                                   k++;
                               }
                           }
                       }                       
                   }
                   dim_buffer = null;
                   fcpos++;
               }
           } catch (IOException e) {
               Utils.FileReadError(inputbin.getName());
           }
           enddate_all = Utils.getMAX(rec_date,nrecords,nb_species);
           startdate_all = Utils.getMIN(rec_date,nrecords,nb_species);
       }
       if (firstrec>startdate_all) firstrec = startdate_all;
       if (lon_min < lonmin) lon_min = lonmin;
       if (lon_max+filereso > lonmax) lon_max = lonmax-filereso+1;
       if (lat_min > latmin) lat_min = latmin;
       if (lat_max-filereso < latmax) lat_max = latmax+filereso-1;
       nlon = (int)(lon_max-lon_min)/filereso+1;
       nlat = (int)(lat_min-lat_max)/filereso+1;
       if ((nlon<0)||(nlat<0)){
           NoData = true;
       }       
       //Point lu = get_lu_index(lon_min, lat_min);
       //Point rl = get_rl_index(lon_max+filereso, lat_max-filereso);
       Point lu = gg.get_index(lon_min, lat_min);
       Point rl = gg.get_index(lon_max+Math.max(filereso,gg.Get_StepX()), lat_max-Math.max(filereso,gg.Get_StepY()));
       nlon_mr = rl.x-lu.x;
       nlat_mr = rl.y-lu.y;
       if (FUNC >= 2){
           nlon_mr = size_x;
           nlat_mr = size_y;
       }
       if (FUNC == 0){
           float dx_reg = gg.Get_StepX();
           float dy_reg = gg.Get_StepY();
           if ((filereso != dx_reg)||(filereso != dy_reg))
               NeedToSplit = true;
       }
       // find the widest time series interval for the species
       // assigned to be transfered on mixed-resolution grid and
       // to be written to the multi-species output file
       nb_series = get_nb_series(startdate_all,enddate_all);
    }
    
    private void ReadParamsTextFile(File inputtxt){
       int header_size = 10;
       try{
            BufferedReader r = new BufferedReader(new FileReader(inputtxt));
            for (int i=0; i<header_size; i++) r.readLine();
            Pos p = new Pos();
            String line = " ";
            line = r.readLine();
            while (line != null){
                nrecords++;
                float year = p.ReadFloat(line);
                float month = p.ReadFloat(line);
                float lat = p.ReadFloat(line);
                float lon = p.ReadFloat(line);        
                float effort = p.ReadFloat(line);
                int k=0;
                if (Criterion == 1){
                    if (effort!=0){
                        if (lat_min < lat) lat_min = lat;
                        if (lat_max > lat) lat_max = lat;
                        if (lon < 0) lon += 360; 
                        if (lon_min > lon) lon_min = lon;
                        if (lon_max < lon) lon_max = lon;
                        for (int sp=0; sp<nb_species; sp++){
                            float date = getDecimal(year,month);
                            if (enddate_all<date) enddate_all = date;
                            if (startdate_all>date) startdate_all = date;
                        }
                    }
                } else if (Criterion == 0){
                    for (int sp=0; sp<nb_species_file; sp++){
                        float value =  p.ReadFloat(line);                       
                        if ((value !=0) && (mr_species[sp]!=0)){
                            if (lat_min < lat) lat_min = lat;
                            if (lat_max > lat) lat_max = lat;
                            if (lon < 0) lon += 360; 
                            if (lon_min > lon) lon_min = lon;
                            if (lon_max < lon) lon_max = lon;
                            float date = getDecimal(year,month);
                            if (enddate_all<date) enddate_all = date;
                            if (startdate_all>date) startdate_all = date;
                            k++;
                        }
                    }
                } else if (Criterion == 2){
                    for (int sp=0; sp<nb_species_file; sp++){
                        float value =  p.ReadFloat(line);                       
                        if ((effort!=0) || (value !=0)){
                            if (mr_species[sp]!=0){
                                if (lat_min < lat) lat_min = lat;
                                if (lat_max > lat) lat_max = lat;
                                if (lon < 0) lon += 360; 
                                if (lon_min > lon) lon_min = lon;
                                if (lon_max < lon) lon_max = lon;
                                float date = getDecimal(year,month);
                                if (enddate_all<date) enddate_all = date;
                                if (startdate_all>date) startdate_all = date;
                                k++;
                            }
                        }
                    }                       
                }
                line = r.readLine();
            } 
            p = null;
       } catch (IOException e) {
           Utils.FileReadError(inputtxt.getName());
       }
        
    }
    
    /*private void CorrectRect(Point lu, Point rl){
        int minx = 100000;
        int maxx = 0;
        int miny = 100000;
        int maxy = 0;
        for (int i=0; i<size_x; i++){
            for (int j=0; j<size_y; j++){
                float lon = gg.xcoord(i,j);
                float lat = gg.ycoord(i,j);
                if ((lat < lat_min)&&(lat>lat_max-filereso)&&
                    (lon > lon_min)&&(lon<lon_max+filereso)){
                        Point p = gg.get_index(lon,lat);
                        if (minx > p.x) minx = p.x;
                        if (maxx < p.x) maxx = p.x;
                        if (miny > p.y) miny = p.y;
                        if (maxy < p.y) maxy = p.y;                        
                }
            }
        }
        nlon_mr = maxx-minx;
        nlat_mr = maxy-miny;
        int test = 0;
    }*/
    
    //======================================================
    // Routine is reading effort and catches for nb_species,  
    // place data into submatrices on nlon x nlat size and
    // create sorted in time data time series
    //======================================================
    private void ReadBinFile(File inputbin){
       ByteBuffer dim_buffer = null;
       int header_size = (6+nb_species_file*2)*4;
       int buffer_size = (4+1+nb_species_file)*4;
       int nbytetoread = (int)inputbin.length()-header_size;
       int nrecords    = nbytetoread/buffer_size;
       try{
           FileInputStream fileInput = new FileInputStream(inputbin);
           FileChannel fc = fileInput.getChannel();
           //=== Start to read data and sort it ===//
           int pos = 0;
           while (pos < nrecords){
               dim_buffer = ByteBuffer.allocate(buffer_size);
               int nbytetoskip = header_size+pos*buffer_size;
               fc.read(dim_buffer,nbytetoskip);
               dim_buffer.order(ByteOrder.LITTLE_ENDIAN);
               dim_buffer.rewind();        
               float year  = dim_buffer.getFloat();
               float month = dim_buffer.getFloat();
               float lat = dim_buffer.getFloat();
               float lon = dim_buffer.getFloat();
               int i = (int) ((lon - lon_min)/filereso);
               if ((i<0)||(i>=nlon)){ 
                   pos++; continue;
               }
               int j = (int) ((lat_min - lat)/filereso);
               if ((j<0)||(j>=nlat)){
                   pos++; continue;
               }
               float Date = getDecimal(year,month);
               if ((startdate_all <= Date)&&(Date <= enddate_all)){
                   int t = get_nb_series(startdate_all,Date)-1;
                   float effort = dim_buffer.getFloat();
                   int k=0;
                   if (Criterion == 1){
                       if (effort != 0){
                           effort_obs[t][i][j] += effort; 
                           for (int sp=0; sp<nb_species_file; sp++){
                               float value =  dim_buffer.getFloat();
                               if (mr_species[sp]!=0){
                                   catch_obs[t][k][i][j] += value;
                                   k++;
                               }
                           }
                       }
                   } else if (Criterion == 0){
                       for (int sp=0; sp<nb_species_file; sp++){
                           float value =  dim_buffer.getFloat();
                           if ((value !=0) && (mr_species[sp]!=0)){
                               catch_obs[t][k][i][j] += value;                               
                               if (k==0)
                                   effort_obs[t][i][j] += effort;
                               k++;
                           }
                       }
                   } else if (Criterion == 2){
                       for (int sp=0; sp<nb_species_file; sp++){
                           float value =  dim_buffer.getFloat();
                           if ((effort !=0)||(value !=0)){
                               if (mr_species[sp]!=0){
                                   catch_obs[t][k][i][j] += value;   
                                   if (k==0)
                                       effort_obs[t][i][j] += effort;                                   
                                   k++;
                               }
                               //effort_obs[t][i][j] = effort;
                           }
                       }                       
                   }
               }
               dim_buffer = null;
               pos++;
           }
       } catch (IOException e) {
           Utils.FileReadError(inputbin.getName());
       }
    }
    
    private void ReadTextFile(File inputtxt){
/*
        String name1 = "_reg7";
        String name2 = "_noreg7";
        String pathname = inputtxt.getAbsolutePath();
        int ss = pathname.indexOf(".");
        String pathname_outp1 = pathname.substring(0,ss)+name1+".txt";
        String pathname_outp2 = pathname.substring(0,ss)+name2+".txt";
        File outtxt1 = new File(pathname_outp1);
        File outtxt2 = new File(pathname_outp2);
*/     
       int header_size = 10;
       int linelength = 5+nb_species_file;
       try{
            BufferedReader r = new BufferedReader(new FileReader(inputtxt));
            for (int i=0; i<header_size; i++) r.readLine();
            Pos p = new Pos();
            String line = r.readLine();
            while (line != null){
                float year = p.ReadFloat(line);
                float month = p.ReadFloat(line);
                float lat = p.ReadFloat(line);
                float lon = p.ReadFloat(line);
/*
            if (lon<=130 && lon>=110 && lat<10 && lat>-10){
            try{
            FileWriter out1 = new FileWriter(outtxt1,true);
            out1.write(line); 
            out1.write("\n");
            out1.close();
            }catch (IOException e) {
                Utils.FileWriteError("./file1.txt");
            }
        }
        else {
            try{
            FileWriter out2 = new FileWriter(outtxt2,true);
            out2.write(line); 
            out2.write("\n");
            out2.close();
            }catch (IOException e) {
                Utils.FileWriteError("./file2.txt");
            }
        }
 **/
                int i = (int) ((lon - lon_min)/filereso);
                if ((i<0)||(i>=nlon)){ 
                    line = r.readLine();
                    p.SetZero(); 
                    continue;
                }
                int j = (int) ((lat_min - lat)/filereso);
                if ((j<0)||(j>=nlat)){
                    line = r.readLine();
                    p.SetZero(); continue;
                }    
                float Date = getDecimal(year,month);
                if ((startdate_all <= Date)&&(Date <= enddate_all)){
                    int t = get_nb_series(startdate_all,Date)-1;
                    float effort = p.ReadFloat(line);
                    int k=0;
                    if (Criterion == 1){
                        if (effort != 0){
                            effort_obs[t][i][j] += effort; 
                            for (int sp=0; sp<nb_species_file; sp++){
                                float value =  p.ReadFloat(line);
                                if (mr_species[sp]!=0){
                                    catch_obs[t][k][i][j] += value;
                                    k++;
                                }
                            }
                        }
                    } else if (Criterion == 0){
                        for (int sp=0; sp<nb_species_file; sp++){
                            float value =  p.ReadFloat(line);
                            if ((value !=0) && (mr_species[sp]!=0)){
                                catch_obs[t][k][i][j] += value;
                                if (k==0)//to avoid adding effort in case of >1 sp
                                    effort_obs[t][i][j] += effort;
                                k++;
                            }
                        }
                    } else if (Criterion == 2){
                        for (int sp=0; sp<nb_species_file; sp++){
                            float value =  p.ReadFloat(line);
                            if ((effort !=0)||(value !=0)){
                                if (mr_species[sp]!=0){
                                    //catch_obs[t][k][i][j] = value;
                                    //if >1 record for the same position exists =>
                                    catch_obs[t][k][i][j] += value;                                 
                                    if (k==0)//to avoid adding effort in case of >1 sp
                                        effort_obs[t][i][j] += effort;   
                                    k++;
                                }
                                //effort_obs[t][i][j] = effort;
                            }
                        }                       
                    }
                }
                line = r.readLine();
            }
            p = null;
       }catch (IOException e) {
           Utils.FileReadError(inputtxt.getName());
       }
    }
    
    private void GetDataLengthForDate(float[][][][] var){
        for (int t=0; t< nb_series; t++){
            nb_data[t] = 0;
            for (int i = 0; i < nlon; i++) {
                for (int j = 0; j < nlat; j++) { 
                    if (AnyNonzero(var[t],i,j))
                        nb_data[t]++;
                }
            }
        }
    }
    
    
    private void GetDataLengthForDate(float[][][] var){
        for (int t=0; t< nb_series; t++){
            nb_data[t] = 0;
            for (int i = 0; i < nlon; i++) {
                for (int j = 0; j < nlat; j++) { 
                    if (var[t][i][j] != 0)
                        nb_data[t]++;
                }
            }
        }
    }
    
    private void GetDataLengthForDate(float[][][] var1, float[][][][] var2){
        for (int t=0; t< nb_series; t++){
            nb_data[t] = 0;
            for (int i = 0; i < nlon; i++) {
                for (int j = 0; j < nlat; j++) { 
                    if ((var1[t][i][j] != 0) || (AnyNonzero(var2[t],i,j)))
                        nb_data[t]++;
                }
            }
        }
    }    
    
    private void GetRDataLengthForDate(float[][] var1, float[][][] var2, int t){
        nb_data[t] = 0;
        for (int i = 0; i < nlon_mr; i++) {
            for (int j = 0; j < nlat_mr; j++) { 
                if ((var1[i][j] != 0)||(AnyNonzero(var2,i,j)))
                    nb_data[t]++;
            }
        }
    }
    
        private boolean AnyNonzero(float[][][] data, int i, int j){
        boolean res = false;
        for (int sp=0; sp<nb_species; sp++){
            if (data[sp][i][j]!=0)
                res=true;
        }
        return res;
    }
    
    private boolean AnyNonzero(float[] data, int n){
        boolean res = false;
        for (int i=0; i<n; i++){
            if ((data[i]!=0)&&(mr_species[i]!=0))
                res=true;
        }
        return res;
    }
    
    private void WriteFile(File outputbin, float[][] effort, float[][][] Catch, int t, int nx, int ny, boolean FileMode, boolean FileType){
        if (FileType)
            WriteBinFile(outputbin,effort,Catch,t,nx,ny,FileMode);
        else
            WriteTextFile(outputbin, effort,Catch,t,nx,ny,FileMode);
    }
    
     private void WriteFile(File outputbin, float[][][] effort, float[][][][] Catch, int nx, int ny, boolean FileType){
        if (FileType)
            WriteBinFile(outputbin,effort,Catch,nx,ny);
        else
            WriteTextFile(outputbin, effort,Catch,nx,ny);
    }
  
    private void WriteBinFile(File outputbin, float[][] effort, float[][][] data, int time, int nx, int ny, boolean FileMode) {
        //Point ij = get_lu_index(lon_min,lat_min);
        Point ij = gg.get_index(lon_min,lat_min);
        int imin = ij.x+1;
        int jmin = ij.y+1;
        if (FUNC>=2){
            imin = 1;
            jmin = 1;
        }        
        try{
            FileOutputStream ofile = new FileOutputStream(outputbin,FileMode);
            if (!FileMode){
                WriteBinFileHeader(ofile);
                WriteDataInFloats(ofile, effort, data, time, nx, ny, imin, jmin);
            } else {
                WriteDataInFloats(ofile, effort, data, time, nx, ny, imin, jmin);
            }
            ofile.close();
        } catch (IOException e) {
            Utils.FileWriteError(outputbin.getName());
        } 
    }
    
   private void WriteBinFile(File outputbin, float[][][] effort, float[][][][] data, int nx, int ny) {
       //Point ij = get_lu_index(lon_min,lat_min);
       //Point ij = gg.get_index(lon_min,lat_min);
       Point ij = gg.get_index(lon_min,lat_min+filereso);
       int imin = ij.x+1;
       int jmin = ij.y+1;
        if (FUNC>=2){
            imin = 1;
            jmin = 1;
        }       
       try{
            FileOutputStream ofile = new FileOutputStream(outputbin);
            WriteBinFileHeader(ofile);
            for (int t=0; t<nb_series; t++){
                WriteDataInFloats(ofile, effort[t], data[t], t, nx, ny, imin, jmin);
                int prDone = (int) ((t+1)*100.0/nb_series);
                IDialog.jProgressBar1.setValue(prDone);
            }
            ofile.close();
        } catch (IOException e) {
            Utils.FileWriteError(outputbin.getName());
        } 
    }

    private void WriteBinFileHeader(OutputStream out) throws IOException {
        int nbyte = 4;
        int ncol  = 3+nb_species;
        //=== Dates of all data in file ======
        Utils.writeFloat(out,startdate_all);
        Utils.writeFloat(out,enddate_all);
        
        //=== Number of species in file ====== 
	Utils.writeInt(out,nb_species);        
        
        //=== Corners of the domain ==========
        Utils.writeFloat(out,lonmin);
        Utils.writeFloat(out,lonmax);
        Utils.writeFloat(out,latmin);
        Utils.writeFloat(out,latmax);
        
        //=== Positions to first,last record for each date === 
        int init_pos = nbyte*(7+nb_series*2);  
        int length = 0;
        for (int t=0; t<nb_series; t++){
            if (nb_data[t] != 0){
                init_pos += length;
                length = nbyte*nb_data[t]*ncol;
                Utils.writeInt(out,init_pos);
                Utils.writeInt(out,nb_data[t]);
            } else {
                Utils.writeInt(out,0);
                Utils.writeInt(out,0);                
            }
        }
    }
      
    private void WriteDataInFloats(FileOutputStream out, float[][] effort, float[][][] data, int time, int nx, int ny, int imin, int jmin) throws IOException {
        //=== DATA: i j effort(i,j) catch(0,i,j),...,catch(nb_species-1,i,j) =====
        
        int bufI = nb_data[time]*2;
        int[] bufferI = new int[bufI];
        int bufF = nb_data[time]*(nb_species+1);
        float[] bufferF = new float[bufF];
        int k=0; int n=0;
        if (nb_data[time] != 0){
        for (int j = 0; j < ny; j++) {
            for (int i = 0; i < nx; i++) {
                boolean write = false;
                if (Criterion == 1){
                    if (effort[i][j] != 0)
                        write = true;
                } else if (Criterion == 0){
                    if (AnyNonzero(data,i,j))
                        write = true;
                }
                else if (Criterion == 2){
                    if ((effort[i][j] != 0) || (AnyNonzero(data,i,j)))
                        write = true;                    
                }
                if (write){
                    if ((k>=bufI))
                        continue;
                    int I = imin+i;
                    int J = jmin+j;
                    bufferI[k]   = I;
                    bufferI[k+1] = J;
                    k += 2;
                    bufferF[n] = effort[i][j];
                    for (int sp=0; sp<nb_species; sp++){
                        bufferF[n+1+sp] = data[sp][i][j];
                    }
                    n += nb_species+1;
                }
            }
        }
        Utils.writeFloat(out,bufferF,bufferI,2+1+nb_species);
        }
    }

    private float getDecimal(float year, float month){
        if ((month > 12)||(year < 1900)) 
            return 0;
        return year+(month-0.5f)/12;
    }
    private int getMonth(float decimal){
        return Math.round((decimal-(int)decimal)*12+0.5f);
    }
    
    private int get_nb_series(float date1, float date2){
        return Math.round((date2 - date1)*12)+1;
    }
    
    private void WriteTextFile(File outputbin, float[][] effort, float[][][] Catch, int time, int nx, int ny, boolean FileMode){
        //Point ij = get_lu_index(lon_min,lat_min);
        Point ij =gg.get_index(lon_min,lat_min);
        int imin = ij.x+1;
        int jmin = ij.y+1;
        if (FUNC>=2){
            imin = 1;
            jmin = 1;
        }        
        try{ 
            FileWriter out = new FileWriter(outputbin, FileMode);
            if (!FileMode){
                WriteTextFileHeader(out);
                WriteTextDataForDate(out,nx,ny,effort,Catch,time,imin,jmin);
            } else {
                WriteTextDataForDate(out,nx,ny,effort,Catch,time,imin,jmin);
            }
            out.close();
        }catch (IOException e) {
            Utils.FileWriteError(outputbin.getName());
        }
    }
    
    private void WriteTextFile(File outputbin, float[][][] effort, float[][][][] Catch, int nx, int ny){
        //Point ij = gg.get_index(lon_min,lat_min);
        Point ij = gg.get_index(lon_min,lat_min+filereso);
        int imin = ij.x+1;
        int jmin = ij.y+1;
        if (FUNC>=2){
            imin = 1;
            jmin = 1;
        }
        try{ 
            FileWriter out = new FileWriter(outputbin);
            WriteTextFileHeader(out);
            for(int t=0; t<nb_series; t++){
                WriteTextDataForDate(out,nx,ny,effort[t],Catch[t],t,imin,jmin);
                int prDone = (int) ((t+1)*100.0/nb_series);
                IDialog.jProgressBar1.setValue(prDone);
            }
            out.close();
        }catch (IOException e) {
            Utils.FileWriteError(outputbin.getName());
        }
    }
    
    private void WriteTextFileHeader(FileWriter out) throws IOException{
        int first_year  = (int)startdate_all;
        int first_month = getMonth(startdate_all);
        int last_year   = (int)enddate_all;
        int last_month  = getMonth(enddate_all);
        out.write(String.valueOf(first_year)); out.write("\t");
        out.write(String.valueOf(first_month)); out.write("\n");
        out.write(String.valueOf(last_year)); out.write("\t");
        out.write(String.valueOf(last_month)); out.write("\n");
        out.write(String.valueOf(nb_species)); out.write("\n");
        out.write(String.valueOf(lonmin)); out.write("\t");
        out.write(String.valueOf(lonmax)); out.write("\t");
        out.write(String.valueOf(latmin)); out.write("\t");
        out.write(String.valueOf(latmax)); out.write("\n");
        out.write(String.valueOf(lon_min)); out.write("\t");
        out.write(String.valueOf(lon_max)); out.write("\t");
        out.write(String.valueOf(lat_min)); out.write("\t");
        out.write(String.valueOf(lat_max)); out.write("\n");        
        int fin_pos = 5+nb_series+1;
        for (int t=0; t<nb_series; t++){
            if (nb_data[t] != 0){
                int init_pos = fin_pos+1;
                fin_pos  = init_pos + nb_data[t]-1;
                out.write(String.valueOf(init_pos)); out.write("\t");
                out.write(String.valueOf(fin_pos)); out.write("\n");
            } else { 
                out.write(String.valueOf(0)); out.write("\t");
                out.write(String.valueOf(0)); out.write("\n");                        
            }
        }
        out.write("\n");
    }
    
    private void WriteTextDataForDate(FileWriter out, int nx, int ny, float[][] effort, float[][][] Catch, int time, int imin, int jmin) throws IOException{
        if (nb_data[time] != 0){
            for (int i=0; i<nx; i++){
                for (int j=0; j<ny; j++){
                    if (Criterion == 1){
                        if (effort[i][j] != 0)
                            WriteTextData(out,i,j,imin,jmin,effort[i][j],Catch);
                    } else if (Criterion == 0){
                        if (AnyNonzero(Catch,i,j))
                            WriteTextData(out,i,j,imin,jmin,effort[i][j],Catch);
                    } else if (Criterion == 2){
                        if ((effort[i][j] != 0)||AnyNonzero(Catch,i,j)){
                            WriteTextData(out,i,j,imin,jmin,effort[i][j],Catch);  
                        }
                    }
                }
            }
        }        
    }
    
    private void WriteTextData(FileWriter out, int i, int j, int imin, int jmin, float effort, float[][][] Catch) throws IOException{
        int I = imin+i;
        int J = jmin+j;
        out.write(String.valueOf(I));  out.write("\t");
        out.write(String.valueOf(J));  out.write("\t");
        out.write(String.valueOf(effort));  out.write("\t");
        for (int sp=0; sp<nb_species; sp++){
            out.write(String.valueOf(Catch[sp][i][j]));  out.write("\t");
        }
        out.write("\n");        
    }
    
    private void Redistribute(float[][] var, float[][] var_mr, int time){
        if (FUNC < 2)
            Redistribute1D(var,var_mr,time);
        else
            Redistribute2D(var,var_mr,time);
    }
    
    private void Redistribute1D(float[][] var, float[][] var_mr, int time){
        Utils.Initialize(var_mr,nlon_mr,nlat_mr);
        float lon,lat;
        //Point p0 = gg.get_index(lon_min,lat_min);
        Point p0 = gg.get_index(lon_min,lat_min+filereso);
        for (int j = 0; j < nlat; j++) {
            for (int i = 0; i < nlon; i++) {
                if (var[i][j] != 0){
                    lon = lon_min + i*filereso;
                    lat = lat_min - j*filereso;
                    Point p1 = gg.get_index(lon,lat);
                    //Point p2 = gg.get_index(lon+filereso,lat-filereso);
                    Point p2 = gg.get_index(lon+filereso,lat+filereso);
                    float q = sq_ratio(p1,p2);
                    //int parts = (p2.x-p1.x)*(p2.y-p1.y);
                    int parts = (p2.x-p1.x)*(p1.y-p2.y);
                    if (parts==0){
                        int iii = p1.x-p0.x;
                        int jjj = p1.y-p0.y;
                        if (iii>=nlon_mr) iii = nlon_mr-1;
                        if (jjj>=nlat_mr) jjj = nlat_mr-1;
                        var_mr[iii][jjj]+=var[i][j];
                    }
                    for (int ii=p1.x; ii<p2.x; ii++){
                        //for (int jj=p1.y; jj<p2.y; jj++){
                        for (int jj=p2.y; jj<p1.y; jj++){
                            int iii = ii-p0.x;
                            int jjj = jj-p0.y;
                            if (jjj<0)
                                jjj=0;
                            if (jjj>=nlat_mr)
                                jjj=nlat_mr-1;
                            double wcoef = ((metric[ii][jj].x*metric[ii][jj].y)/q)/parts;
                            var_mr[iii][jjj] += wcoef*var[i][j];
                        }
                    }
                }
            }
        }  
    }
    
    private void Redistribute2D(float[][] var, float[][] var_mr, int time){
        Utils.Initialize(var_mr,nlon_mr,nlat_mr);
        float lon,lat;
        for (int j = 0; j < nlat; j++) {
            for (int i = 0; i < nlon; i++) {
                if (var[i][j] != 0){
                    lon = lon_min + i*filereso;
                    lat = lat_min - j*filereso;
                    Point p1 = gg.get_index(lon,lat);
                    Point p2 = gg.get_index(lon+filereso,lat-filereso);
                    int i1 = Math.max(0,p1.x-5);
                    int i2 = Math.min(size_x-1,p2.x+5);
                    int j1 = Math.max(0,p1.y-5);
                    int j2 = Math.min(size_y-1,p2.y+5);                    
                    int parts = parts(lon,lat,i1,i2,j1,j2);
                    float q = sq_ratio(lon,lat,i1,i2,j1,j2,parts);
                    for (int ii=i1; ii<i2; ii++){
                        for (int jj=j1; jj<j2; jj++){
                            if ((gg.xcoord(ii,jj)>lon)&&(gg.xcoord(ii,jj)<lon+filereso)&&(gg.ycoord(ii,jj)<lat)&&(gg.ycoord(ii,jj)>lat-filereso)){
                                double wcoef = ((metric[ii][jj].x*metric[ii][jj].y)/q)/parts;
                                var_mr[ii][jj] += wcoef*var[i][j];
                            }
                        }
                    }
                }
            }
        }  
    }
    
    private int parts(float lonmin, float latmin, int i1, int i2, int j1, int j2){
        int parts = 0;
        for (int i=i1; i<i2; i++){
            for (int j=j1; j<j2; j++){
                if ((gg.xcoord(i,j)>lonmin)&&(gg.xcoord(i,j)<lonmin+filereso)&&(gg.ycoord(i,j)<latmin)&&(gg.ycoord(i,j)>latmin-filereso))
                    parts ++;
            }
        }
        return parts;
    }
    
    private float sq_ratio(float lonmin, float latmin, int i1, int i2, int j1, int j2, int parts){
        float ratio = 0;
        for (int i=i1; i<i2; i++){
            for (int j=j1; j<j2; j++){
                if ((gg.xcoord(i,j)>lonmin)&&(gg.xcoord(i,j)<lonmin+filereso)&&(gg.ycoord(i,j)<latmin)&&(gg.ycoord(i,j)>latmin-filereso))
                    ratio += (float)((metric[i][j].x*metric[i][j].y)/parts);
            }
        }
        return ratio;
    }
    
    private float sq_ratio(Point p1, Point p2){
        float ratio = 0;
        int m = p2.x-p1.x;
        //int n = p2.y-p1.y;
        int n = p1.y-p2.y;
        //if (m==0 || n==0) return 1;
        for (int ii=p1.x; ii<p2.x; ii++){
            //for (int jj=p1.y; jj<p2.y; jj++){
            for (int jj=p2.y; jj<p1.y; jj++){
                ratio += (float)((metric[ii][jj].x*metric[ii][jj].y)/(m*n));
            }
        }
        return ratio;
    }

    private float CheckSum(float[][] var, int nx, int ny){
        float sum = 0;
        for (int i = 0; i < nx; i++) {
            for (int j = 0; j < ny; j++) { 
                sum += var[i][j];
            }
        }
        return sum;
    }
    
    /*    private float sq_ratio(Point p1, Point p2){
        float ratio = 0; 
        int n = parts(p1,p2);
        for (int ii=p1.x; ii<=p2.x; ii++){
            for (int jj=p1.y; jj<=p2.y; jj++){
                if (mask[ii][jj]!=0)
                    ratio += (float)((metric[ii][jj].x*metric[ii][jj].y)/n);
            }
        }
        return ratio;
    }
    
    private int parts(Point p1, Point p2){
        int parts = 0;
        for (int ii=p1.x; ii<=p2.x; ii++){
            for (int jj=p1.y; jj<=p2.y; jj++){
                if (mask[ii][jj]!=0)
                    parts ++;
            }
        }
        return parts;
    }*/
}
   
